﻿using SoftwareEngineering.Modeling.DataModeling;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;
using System.Collections.Generic;
using NetFrameworkExtensions;
using System.Diagnostics;
using System.ComponentModel.DataAnnotations;

namespace SoftwareEngineering.Modeling.DataModeling.Tests
{
    
    /// <summary>
    ///This is a test class for DataModelTest and is intended
    ///to contain all DataModelTest Unit Tests
    ///</summary>
  [TestClass()]
  public class DataModelTest
  {


    private TestContext testContextInstance;

    /// <summary>
    ///Gets or sets the test context which provides
    ///information about and functionality for the current test run.
    ///</summary>
    public TestContext TestContext
    {
      get
      {
        return testContextInstance;
      }
      set
      {
        testContextInstance = value;
      }
    }

    public DataModel Model { get; set; }

    [TestInitialize]
    public void InitTest()
    {
      var dir = Environment.CurrentDirectory;
      var dataModel = (DataModel)ModelReader.ReadModel(@"..\..\..\SoftwareEngineering.Tests\Data\DataModel.xml");
      Model = dataModel;
    }

    [TestMethod()]
    public void ReadFromXamlDemoApp()
    {
      Assert.IsNotNull(Model);
      Assert.AreEqual("DemoAppModel", Model.Name);
      Assert.AreEqual("DemoApp", Model.Namespace);
      Assert.AreEqual(DataModelInitType.DropAlways, Model.InitType);
      Assert.AreSame(Model, Model.DataModel);
      Assert.IsNull(Model.Parent);
      Assert.AreSame(Model, Model.Root);
      Assert.IsNull(Model.ParentProperty);
      Assert.IsNotNull(Model.EntityTypes);
      Assert.IsNotNull(Model.DataInitialization);
      Assert.AreEqual(6, Model.EntityTypes.Count);
      Assert.AreEqual(20, Model.DataInitialization.Count);

      var DataModel_EntityType_Property = typeof(DataModel).GetProperty("EntityTypes");
      Assert.IsTrue(Model.EntityTypes.All(e => e != null));
      Assert.IsTrue(Model.EntityTypes.All(e => e.Parent == Model));
      Assert.IsTrue(Model.EntityTypes.All(e => e.ParentProperty == DataModel_EntityType_Property));
    }

    [TestMethod()]
    public void TestEntityKeyConformation()
    {
      var entities = Model.EntityTypes.OrderBy(e => e.Name).ToArray();

      Assert.AreEqual(true, entities.Select(e => e.Name).SequenceEqual(Seq.Build("Group", "Person", "Role", "SecurableAction", "Subject", "User")));

      var key = entities.Single(e => e.Name == "Group").ConformKey().ToArray();

      Assert.AreEqual(1, key.Length);
      Assert.AreEqual("UserId", key[0].KeyName());
      Assert.AreEqual("Guid", key[0].KeyType());

      key = entities.Single(e => e.Name == "Subject").ConformKey().ToArray();

      Assert.AreEqual(1, key.Length);
      Assert.AreEqual("SubjectId", key[0].KeyName());
      Assert.AreEqual("Guid", key[0].KeyType());

      var reference = entities.Single(e => e.Name == "Subject").References.Single(r => r.Name == "Creator");
      key = reference.ConformKey().ToArray();

      Assert.AreEqual(1, key.Length);
      Assert.AreEqual("CreatorId", key[0].KeyName());
      Assert.AreEqual("Guid", key[0].KeyType());

      reference = entities.Single(e => e.Name == "Subject").References.Single(r => r.Name == "ParentSubject");
      key = reference.ConformKey().ToArray();

      Assert.AreEqual(1, key.Length);
      Assert.AreEqual("ParentSubjectId", key[0].KeyName());
      Assert.AreEqual("Guid?", key[0].KeyType());

      foreach (var entity in entities)
      {
        key = entity.ConformKey().ToArray();
        var keyNames = key.ToStringList(", ", k => k.KeyName());
        var keyTypes = key.ToStringList(", ", k => k.KeyName());
      }

      foreach (var refer in entities.SelectMany(e => e.References))
      {
        key = refer.ConformKey().ToArray();
        var keyNames = key.ToStringList(", ", k => k.KeyName());
        var keyTypes = key.ToStringList(", ", k => k.KeyName());
      }
    }

    [TestMethod()]
    public void TestModelValidation()
    {
      var errors = new List<ValidationResult>();
      ModelValidator.TryValidate(Model, null, errors);
      Assert.AreEqual(0, errors.Count);
    }
  }
}
